package com.gn.compile;


/**
 *　　语法分析器。这是PL/0分析器中最重要的部分，在语法分析的过程中穿插着语法错误检查和目标代码生成。
 */
public class Parser {
	private Scanner lex;					// 对词法分析器的引用
	private Table table;					// 对符号表的引用
	private Interpreter interp;				// 对目标代码生成器的引用
	//#获取枚举类型中常量的数量
	private final int symnum = Symbol.values().length;//#可以在声明的时候初始化
	
	// 表示声明开始的符号集合、表示语句开始的符号集合、表示因子开始的符号集合
	// 实际上这就是声明、语句和因子的FIRST集合
	private SymSet declbegsys, statbegsys, facbegsys; //#SymSet是BitSet的包装类
	
	/**
	 * 当前符号，由nextsym()读入
	 * @see #nextSym()
	 */
	private Symbol sym;
	
	/**
	 * 当前作用域的堆栈帧大小，或者说数据大小（data size）
	 */
	//#对应于table中的address
	//# dx应该就是栈中的存放数据时相对于基地址的偏移地址，他也存放着符号表的地址中，栈中存放数据的顺序和符号表中一致
	private int dx = 0;
	
	/**
	 * 构造并初始化语法分析器，这里包含了C语言版本中init()函数的一部分代码
	 * @param l 编译器的词法分析器
	 * @param t 编译器的符号表
	 * @param i 编译器的目标代码生成器
	 */
	public Parser(Scanner l, Table t, Interpreter i) {
		lex = l;
		table = t;
		interp = i;
		
		// 设置声明开始符号集
		declbegsys = new SymSet(symnum);
		declbegsys.set(Symbol.constsym);
		declbegsys.set(Symbol.varsym);
		declbegsys.set(Symbol.procsym);

		// 设置语句开始符号集
		statbegsys = new SymSet(symnum);
		statbegsys.set(Symbol.beginsym);
		statbegsys.set(Symbol.callsym);
		statbegsys.set(Symbol.ifsym);
		statbegsys.set(Symbol.whilesym);
		statbegsys.set(Symbol.readsym);			// thanks to elu
		statbegsys.set(Symbol.writesym);
		/*
			新增
		 */
		statbegsys.set(Symbol.repeat);
		statbegsys.set(Symbol.until);
		statbegsys.set(Symbol.forsym);

		// 设置因子开始符号集
		facbegsys = new SymSet(symnum); //#不用手动改变facbegsys的长度
		facbegsys.set(Symbol.ident); //#因子的开始符号集，一个是常量，一个是标识符，还有一个是左括号
		facbegsys.set(Symbol.number);
		facbegsys.set(Symbol.lparen);
		/*
		* 新增因子的开始符号集
		*/
		facbegsys.set(Symbol.incinc);
		facbegsys.set(Symbol.decdec);
		facbegsys.set(Symbol.sqrt);
	}
	
	/**
	 * 启动语法分析过程，此前必须先调用一次nextsym()
	 * @see #nextSym()
	 */
	public void parse() {
		SymSet nxtlev = new SymSet(symnum); //#后跟符号集，初始化是全为false
		nxtlev.or(declbegsys);//#按位与
		nxtlev.or(statbegsys); //#分程序的后跟符号集可以是声明、语句的开始符号集，但是不可以是因子的开始符号集
		nxtlev.set(Symbol.period); //#相应位设置为TRUE，也可以直接就是程序的结束符
		parseBlock(0, nxtlev); //#使用分程序作为开始符号，而不是程序，0表示当前分程序所在层
		
		if (sym != Symbol.period)
			Err.report(9);
	}
	
	/**
	 * 获得下一个语法符号，这里只是简单调用一下getsym()
	 */
	public void nextSym() {
		lex.getsym();
		sym =lex.sym;
	}
	
	/**
	 * 测试当前符号是否合法
	 * 
	 * @param s1 我们需要的符号
	 * @param s2 如果不是我们需要的，则需要一个补救用的集合
	 * @param errcode 错误号
	 */
	void test(SymSet s1, SymSet s2, int errcode) {
		// 在某一部分（如一条语句，一个表达式）将要结束时时我们希望下一个符号属于某集合
		//（该部分的后跟符号），test负责这项检测，并且负责当检测不通过时的补救措施，程
		// 序在需要检测时指定当前需要的符号集合和补救用的集合（如之前未完成部分的后跟符
		// 号），以及检测不通过时的错误号。
		if (!s1.get(sym)) {  //#下一个符号不在后跟符号集中，报错
			Err.report(errcode);
			// 当检测不通过时，不停获取符号，直到它属于需要的集合或补救的集合
			while (!s1.get(sym) && !s2.get(sym))
				nextSym();
		}
	}
	
	/**
	 * 分析<分程序>
	 * 
	 * @param lev 当前分程序所在层
	 * @param fsys 当前模块后跟符号集
	 */
	public void parseBlock(int lev, SymSet fsys) {
		// <分程序> := [<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句>
		//# fsys后跟符号集
		int dx0, tx0, cx0;				// 保留初始dx，tx和cx
		SymSet nxtlev;
		
		dx0 = dx;						// 记录本层之前的数据量（以便恢复）#当前作用域的堆栈帧大小，或者说数据大小（data size）
		dx = 3;    //# 留出三个位置放静态基址，动态基址，指令指针，对于第一个分程序来说没有用
		tx0 = table.tx;					// 记录本层名字的初始位置（以便恢复）#当前有效的名字表大小（table size）
		//#对于第一个分程序来实是新new符号表的一项，将这一项的地址设置为当前虚拟机代码的指针（最大元素），也就是jmp指令的地址
		//对于定义的分程序来说，是取出已经填入过程名字和层次的一项
		//#下面将jmp指令填入这个cx（虚拟机代码指针）指向的位置，在说明部分分析完成后，使用这个符号表的adr也就是分析之前的cx
		//#找到填入的那句jmp指令，再设置jmp指令的a的值，也就是跳转到哪里，跳过的是分程序说明之后的分程序的内容
		table.get(table.tx).adr = interp.cx;  //#虚拟机代码指针
		interp.gen(Fct.JMP, 0, 0); //# a值首先设置的是0，之后会说明部分分析完成后会改
		
		if (lev > PL0.levmax)
			Err.report(32);
		
		// 分析<说明部分>
		do {
			// <常量说明部分>
			if (sym == Symbol.constsym) {
				nextSym();
				// the original do...while(sym == ident) is problematic, thanks to calculous
				// do
				parseConstDeclaration(lev);
				while (sym == Symbol.comma) {
					nextSym();
					parseConstDeclaration(lev);
				}
				
				if (sym == Symbol.semicolon)
					nextSym();
				else
					Err.report(5);				// 漏掉了逗号或者分号
				// } while (sym == ident);
			}
			
			// <变量说明部分>
			if (sym == Symbol.varsym) {
				nextSym();
				// the original do...while(sym == ident) is problematic, thanks to calculous
				// do {
				parseVarDeclaration(lev);
				while (sym == Symbol.comma)
				{
					nextSym();
					parseVarDeclaration(lev);
				}
				
				if (sym == Symbol.semicolon)
					nextSym();
				else
					Err.report(5);				// 漏掉了逗号或者分号
				// } while (sym == ident);
			}
			
			// <过程说明部分>
			while (sym == Symbol.procsym) //# 这个while循环表示过程说明可以有多个
			{
				nextSym();
				if (sym == Symbol.ident) {
					table.enter(Objekt.procedure, lev, dx); //将procedure的标识符也加入到符号表中，#使用enter，
					//# 标识符的名字就自动填入item.name中了，直接访问了PL0.lex.id
					nextSym();
				} else { 
					Err.report(4);				// procedure后应为标识符
				}

				if (sym == Symbol.semicolon)
					nextSym();
				else
					Err.report(5);				// 漏掉了分号
				
				nxtlev = (SymSet) fsys.clone();
				nxtlev.set(Symbol.semicolon); //#后跟符号集再加上一个分号，过程说明部分最后有一个分号
				parseBlock(lev+1, nxtlev);
				
				if (sym == Symbol.semicolon) {
					nextSym();
					nxtlev = (SymSet) statbegsys.clone();
					nxtlev.set(Symbol.ident);
					nxtlev.set(Symbol.procsym);
					test(nxtlev, fsys, 6);
				} else { 
					Err.report(5);				// 漏掉了分号
				}
			}
			
			nxtlev = (SymSet) statbegsys.clone(); 
			nxtlev.set(Symbol.ident);
			test(nxtlev, declbegsys, 7);
		} while (declbegsys.get(sym));		// 直到没有声明符号
		//#使用do while结构时常量、变量和过程的声明可以不按顺序进行，并且可以多次声明（如多次声明变量）
		
		// 开始生成当前过程代码
		Table.Item item = table.get(tx0); //#如果当前访问的为空，才会new一个，如果本来就存在，直接返回
		//#在之前，item.adr设置为了jmp指令的地址
		interp.code[item.adr].a = interp.cx; //#设置为下一条指令的位置，也就是接下来的语句部分的位置
		item.adr = interp.cx;					// 当前过程代码地址
		item.size = dx;							// 声明部分中每增加一条声明都会给dx增加1，
												// 声明部分已经结束，dx就是当前过程的堆栈帧大小
		cx0 = interp.cx;  //#下一条指令的地址，从语句开始的地址
		interp.gen(Fct.INT, 0, dx);			// 生成分配内存代码 #int就是单纯的分配内存
		
		table.debugTable(tx0);
			
		// 分析<语句>
		nxtlev = (SymSet) fsys.clone();		// 每个后跟符号集和都包含上层后跟符号集和，以便补救
		nxtlev.set(Symbol.semicolon);		// 语句后跟符号为分号或end
		nxtlev.set(Symbol.endsym);
		parseStatement(nxtlev, lev);
		interp.gen(Fct.OPR, 0, 0);		// 每个过程出口都要使用的释放数据段指令
		
		nxtlev = new SymSet(symnum);	    // 分程序没有补救集合
		test(fsys, nxtlev, 8);       // 检测后跟符号正确性
		
		interp.listcode(cx0);               //# 打印p-code指令
		
		dx = dx0;							// 恢复堆栈帧计数器
		table.tx = tx0;						// 回复名字表位置，#这一个分程序作用域结束了，不再需要其中声明的标识符了
	}

	/**
	 * 分析<常量说明部分>
	 * @param lev 当前所在的层次
	 */
	void parseConstDeclaration(int lev) {
		if (sym == Symbol.ident) {
			nextSym();
			if (sym == Symbol.eql || sym == Symbol.becomes) {
				if (sym == Symbol.becomes) 
					Err.report(1);			// 把 = 写成了 :=
				nextSym();
				if (sym == Symbol.number) {
					table.enter(Objekt.constant, lev, dx);
					nextSym();
				} else {
					Err.report(2);			// 常量说明 = 后应是数字
				}
			} else {
				Err.report(3);				// 常量说明标识后应是 =
			}
		} else {
			Err.report(4);					// const 后应是标识符
		}
	}

	/**
	 * 分析<变量说明部分>
	 * @param lev 当前层次
	 */
	void parseVarDeclaration(int lev)
	{
		if (sym == Symbol.ident) //#是普通变量或是数组
		{
			// 填写名字表并改变堆栈帧计数器
			String name = lex.id;
			table.enter(Objekt.variable, lev, dx);  //#无论是普通变量还是数组先把名字表填上，dx记录在数据栈中的起始位置
			dx++; //#这里dx只加了1，如果是数组还要将多出来的空间加上
			nextSym();
			if (sym == Symbol.lparen)//#是数组
			{
				int low, size;
				nextSym();
				low = parseConstAndNum();
				nextSym();
				if (sym == Symbol.colon)
				{
					nextSym();
					int high = parseConstAndNum();
					size = high - low + 1;
					if (size <= 0)
					{
						size = 1; //#避免出错
					}
					//#接下来将table中的变量改为数组
					int array_i = table.position(name);
					Table.Item arrayItem = table.get(array_i);
					arrayItem.val = low; //#将数组的下界放到val里
					dx += size - 1;//#将数组的在数据栈中分配的空间改正确
					nextSym();
					if (sym == Symbol.rparen)
					{
						nextSym();
					}
					else
					{
						Err.report(36);
					}
				}
				else
				{
					Err.report(35);
				}
			}
		}
	}


	private int parseConstAndNum()
	{
		int num = 0;
		if (sym == Symbol.number || sym == Symbol.ident)
		{
			if (sym == Symbol.number)
			{
				num = lex.num;
			}
			else
			{
				int i = table.position(lex.id);
				if (i > 0)
				{
					Table.Item item = table.get(i);
					if (item.kind == Objekt.constant)
					{
						num = item.val;
					} else
					{
						Err.report(34);
					}
				}
				else
				{
					Err.report(11);//#标识符未说明
				}
			}

		}
		else
		{
			Err.report(34);//#数组定义括号中只能为常量或数字
		}

		return num;
	}

	/**
	 * 分析<语句>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	void parseStatement(SymSet fsys, int lev) {
		SymSet nxtlev;
		// Wirth 的 PL/0 编译器使用一系列的if...else...来处理
		// 但是你的助教认为下面的写法能够更加清楚地看出这个函数的处理逻辑
		switch (sym)
		{
		case ident:
			parseAssignStatement(fsys, lev);
			break;
		case readsym:
			parseReadStatement(fsys, lev);
			break;
		case writesym:
			parseWriteStatement(fsys, lev);
			break;
		case callsym:
			parseCallStatement(fsys, lev);
			break;
		case ifsym:
			parseIfStatement(fsys, lev);
			break;
		case beginsym:
			parseBeginStatement(fsys, lev);
			break;
		case whilesym:
			parseWhileStatement(fsys, lev);
			break;
		case incinc:
			parseIncincStatement(fsys, lev);
			break;
		case decdec:
			parseDecdecStatement(fsys, lev);
			break;
		case forsym:
			parseForStatement(fsys,lev);
			break;
		case repeat:
			parseRepeatStatement(fsys, lev);
			break;
		default:
		nxtlev = new SymSet(symnum);
		test(fsys, nxtlev, 19);
		break;
		}
	}


	/**
	 * 新增，repeat循环
	 */
	private void parseRepeatStatement(SymSet fsys, int lev)
	{
		int c1 = interp.cx; //记录一轮结束后跳转的位置
		nextSym();
		parseStatement(fsys, lev);
		if (sym == Symbol.until)
		{
			nextSym();
			parseCondition(fsys, lev);
			interp.gen(Fct.JPC, 0, c1);
		}
		else
		{
			Err.report(42);
		}
	}

	/**
	 * 新增，for循环
	 */
	private void parseForStatement(SymSet fsys, int lev)
	{
		nextSym();
		if (sym == Symbol.ident)
		{
			int i = table.position(lex.id);
			Table.Item item = table.get(i);
			if (item.kind == Objekt.variable)
			{
				parseAssignStatement(fsys, lev);
				if (sym == Symbol.tosym)
				{
					int c1 = interp.cx; //记录循环完一轮之后应该跳转的位置
					nextSym();
					parseExpression(fsys, lev);
					interp.gen(Fct.LOD, lev-item.level, item.adr);
					interp.gen(Fct.OPR, 0, 12);
					int c2 = interp.cx;  //记录跳转指令的位置
					interp.gen(Fct.JPC, 0, 0);  //先设置跳转地址为0
					if (sym == Symbol.dosym)
					{
						nextSym();
						parseStatement(fsys, lev);
						//进行变量加一操作
						interp.gen(Fct.LIT, 0, 1);
						interp.gen(Fct.LOD, lev-item.level, item.adr);
						interp.gen(Fct.OPR, 0, 2);
						interp.gen(Fct.STO, lev-item.level, item.adr);
						interp.gen(Fct.JMP, 0, c1); //循环完一轮之后无条件跳转到比较处
						//设置有条件跳转指令跳转的位置
						interp.code[c2].a = interp.cx;
					}
					else
					{
						Err.report(39);
					}
				}
				else
				{
					Err.report(38);
				}
			}
			else
			{
				Err.report(40);
			}
		}
		else
		{
			Err.report(40);
		}

	}

	/**
	 * 分析<前++>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseIncincStatement(SymSet fsys, int lev)
	{
		nextSym();
		if(sym==Symbol.ident)
		{
			int i=table.position(lex.id);
			if(i==0)
			{
				Err.report(11);
			}
			else
			{
				Table.Item item = table.get(i);
				if(item.kind!=Objekt.variable)
				{
					Err.report(12);
				}
				else //#是普通变量或者是数组
				{
					nextSym();
					if (sym == Symbol.lparen) //#是数组
					{
						nextSym();
						parseExpressionArray(fsys, lev, item.val); //#栈顶放入相对索引
						if (sym == Symbol.rparen)
						{
							interp.gen(Fct.LIT, 0, 1);
							interp.gen(Fct.LODA, lev-item.level, item.adr);
							interp.gen(Fct.RPM, lev-item.level, item.adr); //做加法，存数组，加前的值在相对索引处
							interp.gen(Fct.MOVE, 0, -1); //#栈顶指针向下移动一个
							nextSym();
						}
						else
						{
							Err.report(36);
						}
					}
					else //#是普通变量
					{
						interp.gen(Fct.LOD,lev-item.level,item.adr);
						interp.gen(Fct.LIT,0,1);
						interp.gen(Fct.OPR,0,2);
						interp.gen(Fct.STO,lev-item.level,item.adr);
					}
				}
			}
		}
		else {
			Err.report(37);//#加加减减运算符之后为变量
		}
	}

	/**
	 * 分析<前-->
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseDecdecStatement(SymSet fsys, int lev)
	{
		nextSym();
		if(sym==Symbol.ident)
		{
			int i=table.position(lex.id);
			if(i==0)
			{
				Err.report(11);
			}
			else
			{
				Table.Item item = table.get(i);
				if(item.kind!=Objekt.variable)
				{
					Err.report(12);
				}
				else //#是普通变量或者是数组
				{
					nextSym();
					if (sym == Symbol.lparen) //#是数组
					{
						nextSym();
						parseExpressionArray(fsys, lev, item.val); //#栈顶放入相对索引
						if (sym == Symbol.rparen)
						{
							interp.gen(Fct.LIT, 0, -1);
							interp.gen(Fct.LODA, lev-item.level, item.adr);
							interp.gen(Fct.RPM, lev-item.level, item.adr); //做加法，存数组，加前的值在相对索引处
							interp.gen(Fct.MOVE, 0, -1); //#指针往下移动一个，将数组的值弹出
							nextSym();
						}
						else
						{
							Err.report(36);
						}
					}
					else //#是普通变量
					{
						interp.gen(Fct.LOD,lev-item.level,item.adr);
						interp.gen(Fct.LIT,0,-1);
						interp.gen(Fct.OPR,0,2);
						interp.gen(Fct.STO,lev-item.level,item.adr);
					}
				}
			}
		}
		else {
			Err.report(37);//#加加减减运算符之后为变量
		}
	}
	/**
	 * 分析<当型循环语句>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseWhileStatement(SymSet fsys, int lev) {
		int cx1, cx2;
		SymSet nxtlev;
		
		cx1 = interp.cx;						// 保存判断条件操作的位置
		nextSym();
		nxtlev = (SymSet) fsys.clone();
		nxtlev.set(Symbol.dosym);				// 后跟符号为do
		parseCondition(nxtlev, lev);			// 分析<条件>
		cx2 = interp.cx;						// 保存循环体的结束的下一个位置
		interp.gen(Fct.JPC, 0, 0);				// 生成条件跳转，但跳出循环的地址未知
		if (sym == Symbol.dosym)
			nextSym();
		else
			Err.report(18);						// 缺少do
		parseStatement(fsys, lev);				// 分析<语句>
		interp.gen(Fct.JMP, 0, cx1);			// 回头重新判断条件
		interp.code[cx2].a = interp.cx;			// 反填跳出循环的地址，与<条件语句>类似
	}

	/**
	 * 分析<复合语句>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseBeginStatement(SymSet fsys, int lev) {
		SymSet nxtlev;
		
		nextSym();
		nxtlev = (SymSet) fsys.clone();
		nxtlev.set(Symbol.semicolon);
		nxtlev.set(Symbol.endsym);
		parseStatement(nxtlev, lev);
		// 循环分析{; <语句>}，直到下一个符号不是语句开始符号或收到end
		while (statbegsys.get(sym) || sym == Symbol.semicolon)  //#一个是真，即为真，如果是语句的开始符号或是“；”则继续
		{
			if (sym == Symbol.semicolon)
				nextSym();
			else
				Err.report(10);					// 缺少分号
			parseStatement(nxtlev, lev);
		}
		if (sym == Symbol.endsym)
			nextSym();
		else
			Err.report(17);						// 缺少end或分号
	}

	/**
	 * 分析<条件语句>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseIfStatement(SymSet fsys, int lev) {
		int cx1, cx2;
		SymSet nxtlev;
		
		nextSym();
		nxtlev = (SymSet) fsys.clone();
		nxtlev.set(Symbol.thensym);				// 后跟符号为then或do ???
		nxtlev.set(Symbol.dosym);
		parseCondition(nxtlev, lev);			// 分析<条件>
		if (sym == Symbol.thensym)
			nextSym();
		else
			Err.report(16);						// 缺少then
		cx1 = interp.cx;						// 保存当前指令地址
		//#栈顶为0，进行跳转，跳过then后面的语句
		interp.gen(Fct.JPC, 0, 0);			// 生成条件跳转指令，跳转地址未知，暂时写0
		parseStatement(fsys, lev);				// 处理then后的语句

		if (sym == Symbol.elsesym)
		{
			//#then后的语句后紧跟一个无条件跳转，跳过else后的语句
			cx2 = interp.cx; //#记录无条件跳转指令的位置
			interp.gen(Fct.JMP, 0, 0); //#地址未知，先写0
			interp.code[cx1].a = interp.cx;		// 经statement处理后，cx为then后语句执行
												// 完的位置，它正是前面未定的跳转地址
			nextSym();
			parseStatement(fsys, lev);				//# 处理else后的语句
			interp.code[cx2].a = interp.cx;         //# 之后再设置跳转的地址
		}
		else
		{
			interp.code[cx1].a = interp.cx;		// 经statement处理后，cx为then后语句执行
												// 完的位置，它正是前面未定的跳转地址
		}
	}

	/**
	 * 分析<过程调用语句>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseCallStatement(SymSet fsys, int lev) {
		int i;
		nextSym();
		if (sym == Symbol.ident) {
			i = table.position(lex.id);
			if (i == 0) {
				Err.report(11);					// 过程未找到
			} else {
				Table.Item item = table.get(i);
				if (item.kind == Objekt.procedure)
					interp.gen(Fct.CAL, lev - item.level, item.adr);
					//#过程的地址中放的是指令中语句部分在code中的指针
				else
					Err.report(15);				// call后标识符应为过程
			}
			nextSym();
		} else {
			Err.report(14);						// call后应为标识符
		}
	}

	/**
	 * 分析<写语句>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseWriteStatement(SymSet fsys, int lev) {
		SymSet nxtlev;

		nextSym();
		if (sym == Symbol.lparen) {
			do {
				nextSym();
				nxtlev = (SymSet) fsys.clone();
				nxtlev.set(Symbol.rparen);
				nxtlev.set(Symbol.comma);
				parseExpression(nxtlev, lev);
				interp.gen(Fct.OPR, 0, 14);
			} while (sym == Symbol.comma); //#可以一次写多个表达式，中间使用逗号隔开
			
			if (sym == Symbol.rparen)
				nextSym();
			else
				Err.report(33);				// write()中应为完整表达式
		}
		interp.gen(Fct.OPR, 0, 15); //#最后输出一个换行
	}

	/**
	 * 分析<读语句>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseReadStatement(SymSet fsys, int lev) {
		int i;
		
		nextSym();
		if (sym == Symbol.lparen) {
			do {
				nextSym();
				if (sym == Symbol.ident)
					i = table.position(lex.id);
				else
					i = 0;
				
				if (i == 0) {
					Err.report(35);			// read()中应是声明过的变量名
				} else {
					Table.Item item = table.get(i);
					if (item.kind != Objekt.variable) {
						Err.report(32);		// read()中的标识符不是变量, thanks to amd
					} else {
						interp.gen(Fct.OPR, 0, 16);
						interp.gen(Fct.STO, lev-item.level, item.adr); //#adr作为的是偏移地址，根据层差找到基址
					}
				}
				
				nextSym();
			} while (sym == Symbol.comma);
		} else {
			Err.report(34);					// 格式错误，应是左括号
		}
		
		if (sym == Symbol.rparen) {
			nextSym();
		} else {
			Err.report(33);					// 格式错误，应是右括号
			while (!fsys.get(sym))
				nextSym();
		}
	}

	/**
	 * 分析<赋值语句>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseAssignStatement1(SymSet fsys, int lev)
	{
		int i;
		SymSet nxtlev;
		
		i = table.position(lex.id);
		if (i > 0)
		{
			Table.Item item = table.get(i);
			if (item.kind == Objekt.variable) {
				nextSym();
				if (sym == Symbol.becomes)
					nextSym();
				else
					Err.report(13);					// 没有检测到赋值符号
				nxtlev = (SymSet) fsys.clone();
				parseExpression(nxtlev, lev);
				// parseExpression将产生一系列指令，但最终结果将会保存在栈顶，执行sto命令完成赋值
				interp.gen(Fct.STO, lev - item.level, item.adr);
			} else {
				Err.report(12);						// 赋值语句格式错误
			}
		} else {
			Err.report(11);							// 变量未找到
		}
	}
	private void parseAssignStatement(SymSet fsys, int lev)
	{
		int i;
		SymSet nxtlev;
		i=table.position(lex.id);
		if (i > 0)
		{
			Table.Item item = table.get(i);
			if(item.kind!=Objekt.variable) //判断是不是变量
			{
				Err.report(12);
				i=0;
			}
			else
			{
				nextSym();
				//#判断是不是数组
				if(sym == Symbol.lparen) //#是数组
				{
					nextSym();
					nxtlev = (SymSet) fsys.clone();
					parseExpressionArray(nxtlev, lev, item.val); //#分析 <表达式> 最后将数组的索引存在栈顶
					if(sym == Symbol.rparen)
					{
						nextSym();
						if(sym==Symbol.becomes)
						{
							nextSym();
							nxtlev = (SymSet) fsys.clone();
							parseExpression(nxtlev, lev); //#计算赋值号右边的值
							interp.gen(Fct.STOA, lev - item.level, item.adr);
						}
						else if(sym==Symbol.pluseql)  /*加等于时执行的操作*/
						{
							nextSym();
							nxtlev = (SymSet) fsys.clone();
							parseExpression(nxtlev, lev); //#栈顶存放的是+=右边表达式的值，次栈顶是数组相对索引
							interp.gen(Fct.LODA, lev-item.level, item.adr);
							interp.gen(Fct.OPR, 0, 2);
							interp.gen(Fct.STOA, lev - item.level, item.adr);
						}
						else if(sym==Symbol.incinc)/*自加时执行的操作 */
						{
							nextSym();
							interp.gen(Fct.LIT, 0, 1);//常量1放到栈顶
							interp.gen(Fct.LODA, lev-item.level, item.adr);//将变量放到栈顶
							interp.gen(Fct.OPR, 0 ,2);//栈顶与次栈顶元素相加
							interp.gen(Fct.STOA, lev-item.level, item.adr);//栈顶元素存入栈中变量的位置上
						}
						else if(sym==Symbol.minueql)/*减等时执行的操作*/
						{
							nextSym();
							nxtlev = (SymSet) fsys.clone();
							parseExpression(nxtlev, lev);/*计算等号右边表达式的结果*/
							interp.gen(Fct.LODA, lev-item.level, item.adr);
							interp.gen(Fct.OPR, 0, 3);//次栈顶元素减去栈顶元素
							interp.gen(Fct.OPR, 0 ,1);//栈顶元素取反
							interp.gen(Fct.STOA, lev - item.level, item.adr);
						}
						else if(sym==Symbol.decdec)/*自减时执行的操作*/
						{
							nextSym();
							interp.gen(Fct.LIT, 0, -1);//常量1放到栈顶
							interp.gen(Fct.LODA, lev-item.level, item.adr);//将变量放到栈顶
							interp.gen(Fct.OPR, 0 ,2);//栈顶与次栈顶元素相加
							interp.gen(Fct.STOA, lev-item.level, item.adr);//栈顶元素存入栈中变量的位置上
						}
						else if(sym==Symbol.timeseql)  /*乘等时执行的操作*/
						{
							nextSym();
							nxtlev = (SymSet) fsys.clone();
							parseExpression(nxtlev, lev);/*计算等号右边表达式的结果*/
							interp.gen(Fct.LODA, lev-item.level, item.adr);
							interp.gen(Fct.OPR, 0, 4);
							interp.gen(Fct.STOA, lev - item.level, item.adr);
						}
						else if(sym==Symbol.slasheql)  /*除等时执行的操作*/
						{
							nextSym();
							nxtlev = (SymSet) fsys.clone();
							parseExpression(nxtlev, lev);/*计算等号右边表达式的结果*/
							interp.gen(Fct.LODA, lev-item.level, item.adr);
							interp.gen(Fct.OPR, 0, 18); //新增加的操作，栈顶元素除以次栈顶元素
							interp.gen(Fct.STOA, lev - item.level, item.adr);
						}
					}
					else
					{
						Err.report(36);
					}
				}
				else //#不是数组
				{
					if(sym==Symbol.becomes)
					{
						nextSym();
						nxtlev = (SymSet) fsys.clone();
						parseExpression(nxtlev, lev);
						interp.gen(Fct.STO, lev - item.level, item.adr);
					}
					else if(sym==Symbol.pluseql)  /*加等于时执行的操作*/
					{
						nextSym();
						nxtlev = (SymSet) fsys.clone();
						parseExpression(nxtlev, lev);
						interp.gen(Fct.LOD, lev-item.level, item.adr);
						interp.gen(Fct.OPR, 0, 2);
						interp.gen(Fct.STO, lev - item.level, item.adr);
					}
					else if(sym==Symbol.incinc)/*自加时执行的操作 */
					{
						nextSym();
						interp.gen(Fct.LOD, lev-item.level, item.adr);//将变量放到栈顶
						interp.gen(Fct.LIT, 0, 1);//常量1放到栈顶
						interp.gen(Fct.OPR, 0 ,2);//栈顶与次栈顶元素相加
						interp.gen(Fct.STO, lev-item.level, item.adr);//栈顶元素存入栈中变量的位置上
					}
					else if(sym==Symbol.minueql)/*减等时执行的操作*/
					{
						nextSym();
						nxtlev = (SymSet) fsys.clone();
						parseExpression(nxtlev, lev);/*计算等号右边表达式的结果*/
						interp.gen(Fct.LOD, lev-item.level, item.adr);
						interp.gen(Fct.OPR, 0, 3);//次栈顶元素减去栈顶元素
						interp.gen(Fct.OPR, 0 ,1);//栈顶元素取反
						interp.gen(Fct.STO, lev - item.level, item.adr);
					}
					else if(sym==Symbol.decdec)/*自减时执行的操作*/
					{
						nextSym();
						interp.gen(Fct.LOD, lev-item.level, item.adr);//将变量放到栈顶
						interp.gen(Fct.LIT, 0, -1);//常量1放到栈顶
						interp.gen(Fct.OPR, 0 ,2);//栈顶与次栈顶元素相加
						interp.gen(Fct.STO, lev-item.level, item.adr);//栈顶元素存入栈中变量的位置上
					}
					else if(sym==Symbol.timeseql)  /*乘等时执行的操作*/
					{
						nextSym();
						nxtlev = (SymSet) fsys.clone();
						parseExpression(nxtlev, lev);/*计算等号右边表达式的结果*/
						interp.gen(Fct.LOD, lev-item.level, item.adr);
						interp.gen(Fct.OPR, 0, 4);
						interp.gen(Fct.STO, lev - item.level, item.adr);
					}
					else if(sym==Symbol.slasheql)  /*除等时执行的操作*/
					{
						nextSym();
						nxtlev = (SymSet) fsys.clone();
						parseExpression(nxtlev, lev);/*计算等号右边表达式的结果*/
						interp.gen(Fct.LOD, lev-item.level, item.adr);
						interp.gen(Fct.OPR, 0, 18); //新增加的操作，栈顶元素除以次栈顶元素
						interp.gen(Fct.STO, lev - item.level, item.adr);
					}
				}
			}
		}
		else
		{
			Err.report(11); // 变量未找到
		}
	}

	/**
	 * 分析<表达式>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseExpression(SymSet fsys, int lev) {
		Symbol addop;
		SymSet nxtlev;
		
		// 分析[+|-]<项>
		if (sym == Symbol.plus || sym == Symbol.minus || sym == Symbol.exclam || sym == Symbol.sqrt) {
			addop = sym;
			nextSym();
			nxtlev = (SymSet) fsys.clone();
			nxtlev.set(Symbol.plus);
			nxtlev.set(Symbol.minus);
			parseTerm(nxtlev, lev);
			if (addop == Symbol.minus)
			{
				interp.gen(Fct.OPR, 0, 1);
			}
			else if (addop == Symbol.exclam)
			{
				interp.gen(Fct.OPR, 0, 20);
			}
			else if (addop == Symbol.sqrt)
			{
				interp.gen(Fct.OPR, 0, 17);
			}
		} else {
			nxtlev = (SymSet) fsys.clone();
			nxtlev.set(Symbol.plus);
			nxtlev.set(Symbol.minus);
			parseTerm(nxtlev, lev);
		}
		
		// 分析{<加法运算符><项>}
		while (sym == Symbol.plus || sym == Symbol.minus) {
			addop = sym;
			nextSym();
			nxtlev = (SymSet) fsys.clone();
			nxtlev.set(Symbol.plus);
			nxtlev.set(Symbol.minus);
			parseTerm(nxtlev, lev);
			if (addop == Symbol.plus)
				interp.gen(Fct.OPR, 0, 2);
			else
				interp.gen(Fct.OPR, 0, 3);
		}
	}

	/**
	 * 新增加，用于分析数组索引中的表达式，生成将数组的相对索引存入栈顶的代码
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 * @param low 数组下界
	 */
	private void parseExpressionArray(SymSet fsys, int lev, int low) {
		Symbol addop;
		SymSet nxtlev;

		// 分析[+|-]<项>
		if (sym == Symbol.plus || sym == Symbol.minus || sym == Symbol.exclam || sym == Symbol.sqrt) {
			addop = sym;
			nextSym();
			nxtlev = (SymSet) fsys.clone();
			nxtlev.set(Symbol.plus);
			nxtlev.set(Symbol.minus);
			parseTerm(nxtlev, lev);
			if (addop == Symbol.minus)
			{
				interp.gen(Fct.OPR, 0, 1);
			}
			else if (addop == Symbol.exclam)
			{
				interp.gen(Fct.OPR, 0, 20);
			}
			else if (addop == Symbol.sqrt)
			{
				interp.gen(Fct.OPR, 0, 17);
			}
		} else {
			nxtlev = (SymSet) fsys.clone();
			nxtlev.set(Symbol.plus);
			nxtlev.set(Symbol.minus);
			parseTerm(nxtlev, lev);
		}

		// 分析{<加法运算符><项>}
		while (sym == Symbol.plus || sym == Symbol.minus) {
			addop = sym;
			nextSym();
			nxtlev = (SymSet) fsys.clone();
			nxtlev.set(Symbol.plus);
			nxtlev.set(Symbol.minus);
			parseTerm(nxtlev, lev);
			if (addop == Symbol.plus)
				interp.gen(Fct.OPR, 0, 2);
			else
				interp.gen(Fct.OPR, 0, 3);
		}
		//#将最终结果计算完放到栈顶之后再将计算相对索引
		interp.gen(Fct.LIT, 0, low); //#将数组的下界放到栈顶
		interp.gen(Fct.OPR, 0, 3); //#次栈顶减去栈顶，得到相对偏移量
	}
	/**
	 * 分析<项>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseTerm(SymSet fsys, int lev) {
		Symbol mulop;
		SymSet nxtlev;

		// 分析<因子>
		nxtlev = (SymSet) fsys.clone();
		nxtlev.set(Symbol.times);
		nxtlev.set(Symbol.slash);
		nxtlev.set(Symbol.percent);
		parseFactor(nxtlev, lev);
		
		// 分析{<乘法运算符><因子>}
		/*
		* 新增加取模操作符
		 */
		while (sym == Symbol.times || sym == Symbol.slash || sym == Symbol.percent) {
			mulop = sym;
			nextSym();
			parseFactor(nxtlev, lev);
			if (mulop == Symbol.times)
				interp.gen(Fct.OPR, 0, 4);
			else if (mulop == Symbol.slash)
				interp.gen(Fct.OPR, 0, 5);
			else
				interp.gen(Fct.OPR, 0 ,19); //次栈顶元素对栈顶元素取模
		}
	}

	/**
	 * 分析<因子>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseFactor1(SymSet fsys, int lev)
	{
		SymSet nxtlev;
		
		test(facbegsys, fsys, 24);			// 检测因子的开始符号
		if (facbegsys.get(sym))
		{
			if (sym == Symbol.ident)
			{			// 因子为常量或变量
				int i = table.position(lex.id);
				if (i > 0)
				{
					Table.Item item = table.get(i);
					switch (item.kind)
					{
					case constant:			// 名字为常量
						interp.gen(Fct.LIT, 0, item.val);
						break;
					case variable:			// 名字为变量
						interp.gen(Fct.LOD, lev - item.level, item.adr);
						break;
					case procedure:			// 名字为过程
						Err.report(21);				// 不能为过程
						break;
					}
				} else {
					Err.report(11);					// 标识符未声明
				}
				nextSym();
			}
			else if (sym == Symbol.number)
			{	// 因子为数
				int num = lex.num;
				if (num > PL0.amax) {
					Err.report(31);
					num = 0;
				}
				interp.gen(Fct.LIT, 0, num);
				nextSym();
			}
			else if (sym == Symbol.lparen)
			{	// 因子为表达式
				nextSym();
				nxtlev = (SymSet) fsys.clone();
				nxtlev.set(Symbol.rparen);
				parseExpression(nxtlev, lev);
				if (sym == Symbol.rparen)
					nextSym();
				else
					Err.report(22);					// 缺少右括号
			}
			else
			{
				// 做补救措施
				test(fsys, facbegsys, 23);
			}
		}
	}

	/**
	 * 新增， 分析<因子>
	 * 增加对++|--的支持
	 * 增加对数组的支持
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseFactor(SymSet fsys, int lev)
	{
		SymSet nxtlev;
		test(facbegsys, fsys, 24);            // 检测因子的开始符号
		if (facbegsys.get(sym))
		{
			if (sym == Symbol.ident)
			{            // 因子为常量或变量或是数组
				int i = table.position(lex.id);
				if (i > 0)
				{
					Table.Item item = table.get(i);
					switch (item.kind)
					{
						case constant:            // 名字为常量
							interp.gen(Fct.LIT, 0, item.val);
							nextSym();
							break;
						case variable:            // 名字为变量或数组
							nextSym();
							if (sym == Symbol.lparen) //#是数组
							{
								nextSym();
								parseExpressionArray(fsys, lev, item.val);//#将计算出的数组的相对索引放到栈顶
								if (sym == Symbol.rparen)
								{
									nextSym();
									if (sym == Symbol.incinc) //# <id>(<表达式>)++
									{
										interp.gen(Fct.LIT, 0, 1);
										interp.gen(Fct.LODA, lev-item.level, item.adr); //#将变量加载到栈顶
										//#将次栈顶元素与栈顶元素相加存入数组中，并将相加前的数组的值放到索引位置
										interp.gen(Fct.RPM, lev-item.level, item.adr);
										nextSym();
									}
									else if (sym == Symbol.decdec)  //# <id>(<表达式>)--
									{
										interp.gen(Fct.LIT, 0, -1);
										interp.gen(Fct.LODA, lev-item.level, item.adr); //#将变量加载到栈顶
										//#将次栈顶元素与栈顶元素相加存入数组中，并将相加前的数组的值放到索引位置
										interp.gen(Fct.RPM, lev-item.level, item.adr);
										nextSym();
									}
									else //# <id>(<表达式>)
									{
										//#在这需要的是将数组的值放到栈顶，不需要次栈有数组的索引
										interp.gen(Fct.LODA2, lev - item.level, item.adr);
									}
									break;
								}
								else
								{
									Err.report(36);
								}
							}
							else //#是普通变量
							{
								if (sym == Symbol.incinc) //# <id>++
								{
									interp.gen(Fct.LOD, lev-item.level, item.adr); //#将变量加载到栈顶
									interp.gen(Fct.LOD, lev-item.level, item.adr); //#再加载一遍
									interp.gen(Fct.LIT, 0, 1);
									interp.gen(Fct.OPR, 0, 2);//#栈顶与次栈顶相加
									//#加完之后的数存回变量，栈顶留下加之前的
									interp.gen(Fct.STO, lev-item.level, item.adr);
									nextSym();
								}
								else if (sym == Symbol.decdec)  //# <id>--
								{
									interp.gen(Fct.LOD, lev-item.level, item.adr); //#将变量加载到栈顶
									interp.gen(Fct.LOD, lev-item.level, item.adr); //#再加载一遍
									interp.gen(Fct.LIT, 0, -1);
									interp.gen(Fct.OPR, 0, 2);//#栈顶与次栈顶相加
									//#加完之后的数存回变量，栈顶留下加之前的
									interp.gen(Fct.STO, lev-item.level, item.adr);
									nextSym();
								}
								else //# <id>
								{
									interp.gen(Fct.LOD, lev - item.level, item.adr);
								}
								break;
							}
						case procedure:            // 名字为过程
							Err.report(21);                // 不能为过程
							nextSym();
							break;
					}
				}
				else
				{
					Err.report(11);                    // 标识符未声明
				}

			}
			else if (sym == Symbol.incinc || sym == Symbol.decdec) //# [++|--]<id>[(<索引表达式>)]
			{
				Symbol oper = sym;
				nextSym();
				if (sym == Symbol.ident) //# <id>
				{
					int i = table.position(lex.id);
					if (i > 0)
					{
						Table.Item item = table.get(i);
						if (item.kind == Objekt.variable) //#是变量或是数组
						{
							nextSym();
							if (sym == Symbol.lparen) //#是数组
							{
								nextSym();
								parseExpressionArray(fsys, lev, item.val);
								if (sym == Symbol.rparen)
								{
									if (oper == Symbol.incinc)  //# 前加加
									{
										interp.gen(Fct.LIT, 0, 1);
										interp.gen(Fct.LODA, lev-item.level, item.adr);
										interp.gen(Fct.RPM, lev-item.level, item.adr); //做加法，存数组，加前的值在相对索引处
										interp.gen(Fct.LIT, 0, 1);
										interp.gen(Fct.OPR, 0, 2);//#当前栈顶是加之前的值，再加一次，前++返回的是加之后的值
									}
									else  //# 前减减
									{
										interp.gen(Fct.LIT, 0, -1);
										interp.gen(Fct.LODA, lev-item.level, item.adr);
										interp.gen(Fct.RPM, lev-item.level, item.adr); //做加法，存数组，加前的值在相对索引处
										interp.gen(Fct.LIT, 0, -1);
										interp.gen(Fct.OPR, 0, 2);//#当前栈顶是加之前的值，再加一次，前++返回的是加之后的值
									}
									nextSym();
								}
								else
								{
									Err.report(36);
								}
							}
							else //#是普通变量
							{
								if (oper == Symbol.incinc)  //# 前加加
								{
									interp.gen(Fct.LOD, lev-item.level, item.adr); //#加载到栈顶
									interp.gen(Fct.LIT, 0, 1);
									interp.gen(Fct.OPR, 0, 2); //#次栈顶与栈顶元素相加，放到次栈顶
									//#将加完的元素存入原来变量在栈中的位置
									interp.gen(Fct.STO, lev-item.level, item.adr);
									interp.gen(Fct.LOD, lev-item.level, item.adr); //#将加完的变量再次加载到栈顶
								}
								else  //# 前减减
								{
									interp.gen(Fct.LOD, lev-item.level, item.adr); //#加载到栈顶
									interp.gen(Fct.LIT, 0, -1);
									interp.gen(Fct.OPR, 0, 2); //#次栈顶与栈顶元素相加，放到次栈顶
									//#将加完的元素存入原来变量在栈中的位置
									interp.gen(Fct.STO, lev-item.level, item.adr);
									interp.gen(Fct.LOD, lev-item.level, item.adr); //#将加完的变量再次加载到栈顶
								}
							}
						}
						else
						{
							Err.report(33);
						}
					}
					else
					{
						Err.report(11);
					}
				}
				else
				{
					Err.report(33);
				}
			}
			else if (sym == Symbol.number)
			{    // 因子为数
				int num = lex.num;
				if (num > PL0.amax)
				{
					Err.report(31);
					num = 0;
				}
				interp.gen(Fct.LIT, 0, num);
				nextSym();
			}
			else if (sym == Symbol.lparen)
			{    // 因子为表达式
				nextSym();
				nxtlev = (SymSet) fsys.clone();
				nxtlev.set(Symbol.rparen);
				parseExpression(nxtlev, lev);
				if (sym == Symbol.rparen)
					nextSym();
				else
					Err.report(22);                    // 缺少右括号
			}
			else if (sym == Symbol.sqrt)
			{
				nextSym();
				if (sym == Symbol.lparen)
				{
					nextSym();
					parseExpression(fsys, lev);
					interp.gen(Fct.OPR, 0, 17);
					if (sym == Symbol.rparen)
						nextSym();
					else
						Err.report(22);
				}
				else
				{
					Err.report(41);
				}
			}
			else
			{
				// 做补救措施
				test(fsys, facbegsys, 23);
			}
		}
	}
	/**
	 * 分析<条件>
	 * @param fsys 后跟符号集
	 * @param lev 当前层次
	 */
	private void parseCondition(SymSet fsys, int lev) {
		Symbol relop;
		SymSet nxtlev;
		
		if (sym == Symbol.oddsym) {
			// 分析 ODD<表达式>
			nextSym();
			parseExpression(fsys, lev);
			interp.gen(Fct.OPR, 0, 6);
		} else {
			// 分析<表达式><关系运算符><表达式>
			nxtlev = (SymSet) fsys.clone();
			nxtlev.set(Symbol.eql);
			nxtlev.set(Symbol.neq);
			nxtlev.set(Symbol.lss);
			nxtlev.set(Symbol.leq);
			nxtlev.set(Symbol.gtr);
			nxtlev.set(Symbol.geq);
			parseExpression(nxtlev, lev);
			if (sym == Symbol.eql || sym == Symbol.neq 
					|| sym == Symbol.lss || sym == Symbol.leq
					|| sym == Symbol.gtr || sym == Symbol.geq) {
				relop = sym;
				nextSym();
				parseExpression(fsys, lev);
				switch (relop) {
				case eql:
					interp.gen(Fct.OPR, 0, 8);
					break;
				case neq:
					interp.gen(Fct.OPR, 0, 9);
					break;
				case lss:
					interp.gen(Fct.OPR, 0, 10);
					break;
				case geq:
					interp.gen(Fct.OPR, 0, 11);
					break;
				case gtr:
					interp.gen(Fct.OPR, 0, 12);
					break;
				case leq:
					interp.gen(Fct.OPR, 0, 13);
					break;
				}
			} else {
				Err.report(20);
			}
		}
	}
}
